﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using TribesPSO;

namespace GaussianBenchmark
{
    class Program
    {
        /// <summary>
        /// This is a toy program that parses a data file (Data.txt) and attempt to do a curve fit.  The data is the superposition of
        /// several gaussian curves.  This program attempts to extract the original component curves from the data.
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            List<Tuple<double, double>> FitData = ParseFitData("Data.txt");

            Console.WriteLine("********** Single Threaded Indepedent Gaussian **********");
            string gaussianResults = RunIndependentGaussian(10, FitData);
            Console.WriteLine(gaussianResults);
            Console.WriteLine();

            Console.WriteLine("********** Multi Threaded Independent Gaussian **********");
            string multiThreadedGaussianResults = RunMultiThreadedGaussian(10, FitData);
            Console.WriteLine(multiThreadedGaussianResults);
            Console.WriteLine();

            Console.ReadLine();
        }

        //Parse a CSV file to use its data
        private static List<Tuple<double, double>> ParseFitData(string path)
        {
            string[] lines = File.ReadAllLines(path);
            List<Tuple<double,double>> data = new List<Tuple<double, double>>();
            for (int n = 0; n < lines.Length; n++)
            {
                data.Add(new Tuple<double, double>((double)n, double.Parse(lines[n])));
            }
            return data;
        }

        static string RunMultiThreadedGaussian(int loops, List<Tuple<double,double>> fitData)
        {
            double volume = fitData.Sum(o => o.Item2);
            List<int> EvalCount = new List<int>();
            List<TimeSpan> Runtimes = new List<TimeSpan>();
            int successCount = 0;

            for (int n = 0; n < loops; n++)
            {
                GaussianFitFunction objectiveFunction = new GaussianFitFunction(2, fitData);
                var SearchSpace = new MultithreadedGaussianSearchSpace(objectiveFunction);

                DateTime start = DateTime.Now;
                for (int moves = 0; moves < 2500; moves++)
                {
                    SearchSpace.MoveThenAdapt();
                    if (SearchSpace.BestSolution.Error < .5)
                    {
                        successCount += 1;
                        break;
                    }
                }
                DateTime finish = DateTime.Now;

                EvalCount.Add(objectiveFunction.Evaluations);
                Runtimes.Add(new TimeSpan(finish.Ticks - start.Ticks));
            }

            StringBuilder resultBuilder = new StringBuilder();
            resultBuilder.AppendLine("********** Average Evaluations **********");
            resultBuilder.AppendLine(EvalCount.Average().ToString());
            resultBuilder.AppendLine("********** % Success **********");
            resultBuilder.AppendLine(((double)successCount / (double)loops).ToString("F4"));
            resultBuilder.AppendLine("********** Time **********");
            resultBuilder.AppendLine("Average Time: " + new TimeSpan((long)Runtimes.Average(o => o.Ticks)).ToString());
            resultBuilder.AppendLine("Total Time: " + new TimeSpan(Runtimes.Sum(o => o.Ticks)).ToString());

            return resultBuilder.ToString();
        }

        static string RunIndependentGaussian(int loops, List<Tuple<double,double>> fitData)
        {
            double volume = fitData.Sum(o => o.Item2);
            List<int> EvalCount = new List<int>();
            List<TimeSpan> Runtimes = new List<TimeSpan>();
            int successCount = 0;

            for (int n = 0; n < loops; n++)
            {
                GaussianFitFunction objectiveFunction = new GaussianFitFunction(2, fitData);
                var SearchSpace = new SingleThreadedGaussianSearchSpace(objectiveFunction, new HyperspaceRandom());

                DateTime start = DateTime.Now;
                for (int moves = 0; moves < 2500; moves++)
                {
                    SearchSpace.MoveThenAdapt();
                    if (SearchSpace.BestSolution.Error < .5)
                    {
                        successCount += 1;
                        break;
                    }
                }
                DateTime finish = DateTime.Now;

                EvalCount.Add(objectiveFunction.Evaluations);
                Runtimes.Add(new TimeSpan(finish.Ticks - start.Ticks));
            }

            StringBuilder resultBuilder = new StringBuilder();
            resultBuilder.AppendLine("********** Average Evaluations **********");
            resultBuilder.AppendLine(EvalCount.Average().ToString());
            resultBuilder.AppendLine("********** % Success **********");
            resultBuilder.AppendLine(((double)successCount / (double)loops).ToString("F4"));
            resultBuilder.AppendLine("********** Time **********");
            resultBuilder.AppendLine("Average Time: " + new TimeSpan((long)Runtimes.Average(o => o.Ticks)).ToString());
            resultBuilder.AppendLine("Total Time: " + new TimeSpan(Runtimes.Sum(o => o.Ticks)).ToString());

            return resultBuilder.ToString();
        }
    }
}
